home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / Tools / linuxdoc-sgml-1.1 / sgmls-1.1 / main.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-03  |  12.9 KB  |  603 lines

  1. /* main.c -
  2.    Main program for sgmls.
  3.  
  4.      Written by James Clark (jjc@jclark.com).
  5. */
  6.  
  7. #include "config.h"
  8. #include "std.h"
  9. #include "getopt.h"
  10. #include "entity.h"           /* Templates for entity control blocks. */
  11. #include "adl.h"              /* Definitions for attribute list processing. */
  12. #include "sgmlmain.h"         /* Main interface to SGML services. */
  13. #include "appl.h"
  14.  
  15. #define READCNT 512
  16.  
  17. /* Before using argv[0] in error messages, strip off everything up to and
  18. including the last character in prog that occurs in PROG_PREFIX. */
  19.  
  20. #ifndef PROG_PREFIX
  21. #define PROG_PREFIX "/"
  22. #endif /* not PROG_PREFIX */
  23.  
  24. /* Message catalogue name. */
  25. #define CAT_NAME "sgmls"
  26. /* Message set to use for application error messages. */
  27. #define APP_SET 4
  28.  
  29. #ifdef HAVE_EXTENDED_PRINTF
  30. #define xvfprintf vfprintf
  31. #else
  32. extern int xvfprintf P((FILE *, char *, va_list));
  33. #endif
  34.  
  35. static VOID usage P((void));
  36. static VOID fatal VP((int, ...));
  37. static VOID do_error P((int, va_list));
  38. static VOID swinit P((struct switches *));
  39. static VOID write_caps P((char *, struct sgmlcap *));
  40.  
  41. static UNIV make_docent P((int, char **));
  42. static char *munge_program_name P((char *, char *));
  43. static VOID die P((void));
  44. #ifdef SUPPORT_SUBDOC
  45. static VOID build_subargv P((struct switches *));
  46. static VOID cleanup P((void));
  47. static char *create_subcap_file P((void));
  48. #endif /* SUPPORT_SUBDOC */
  49.  
  50. static char *errlist[] = {
  51.      0,
  52.      "Out of memory",
  53.      "Cannot open SGML document entity",
  54.      "Cannot exec `%s': %s",
  55.      "Cannot fork: %s",
  56.      "Error waiting for process: %s",
  57.      "Program %s got fatal signal %d",
  58.      "Cannot open `%s': %s",
  59.      "Subdocument capacity botch",
  60.      "Non-existent subdocument entity `%s' not processed",
  61. };
  62.  
  63. int suppsw = 0;            /* Non-zero means suppress output. */
  64. int locsw = 0;            /* Non-zero means generate location info. */
  65. static char *prog;        /* Program name (for error messages). */
  66. static nl_catd catd;        /* Message catalogue descriptor. */
  67. static char *capfile = 0;    /* File for capacity report. */
  68. extern char *version_string;
  69.  
  70. char options[] = {
  71.      'c', ':', 'd', 'e', 'g', 'i', ':', 'l', 'o', ':', 'p', 'r', 's', 'u', 'v',
  72. #ifdef CANT_REDIRECT_STDERR
  73.      'f', ':',
  74. #endif /* CANT_REDIRECT_STDERR */
  75. #ifdef TRACE
  76.      'x', ':', 'y', ':',
  77. #endif /* TRACE */
  78.      '\0'
  79. };
  80.  
  81. #ifdef SUPPORT_SUBDOC
  82. int suberr = 0;            /* Error in subdocument. */
  83. static char *subargv[sizeof(options)];
  84. static int subargc = 0;
  85. static char nopenbuf[sizeof(long)*3 + 1];
  86. static char sgmldecl_file[L_tmpnam];
  87. static char subcap_file[L_tmpnam];
  88. #endif
  89.  
  90. int main(argc, argv)
  91. int argc;
  92. char **argv;
  93. {
  94.      static char stderr_buf[BUFSIZ];
  95.      int opt;
  96. #ifdef CANT_REDIRECT_STDERR
  97.      char *errfile = 0;
  98. #endif
  99.      struct sgmlcap cap;
  100.      struct switches sw;
  101.      int nincludes = 0;          /* number of -i options */
  102.      setbuf(stderr, stderr_buf);
  103.  
  104.      /* Define MAIN_HOOK in config.h if some function needs to be called here. */
  105. #ifdef MAIN_HOOK
  106.      MAIN_HOOK(argc, argv);
  107. #endif
  108. #ifdef SUPPORT_SUBDOC
  109.      subargv[subargc++] = argv[0];
  110. #endif
  111.  
  112.      prog = argv[0] = munge_program_name(argv[0], "sgmls");
  113.  
  114.      catd = catopen(CAT_NAME, 0);
  115.      swinit(&sw);
  116.  
  117.      while ((opt = getopt(argc, argv, options)) != EOF) {
  118.       switch (opt) {
  119.       case 'l':          /* Generate location information. */
  120.            locsw = 1;
  121.            break;
  122.       case 'c':          /* Print capacity usage. */
  123.            capfile = optarg;
  124.            break;
  125.       case 's':          /* Suppress output. */
  126.            suppsw = 1;
  127.            break;
  128.       case 'd':           /* Report duplicate entity declarations. */
  129.            sw.swdupent = 1;
  130.            break;
  131.       case 'e':           /* Provide entity stack trace in error msg. */
  132.            sw.swenttr = 1;
  133.            break;
  134. #ifdef CANT_REDIRECT_STDERR
  135.       case 'f':          /* Redirect errors. */
  136.            errfile = optarg;
  137.            break;
  138. #endif /* CANT_REDIRECT_STDERR */
  139.       case 'g':           /* Provide GI stack trace in error messages. */
  140.            sw.sweltr = 1;
  141.            break;
  142.       case 'p':          /* Parse only the prolog. */
  143.            sw.onlypro = 1;
  144.            suppsw = 1;
  145.            break;
  146.       case 'r':           /* Give warning for defaulted references. */
  147.            sw.swrefmsg = 1;
  148.            break;
  149.       case 'u':
  150.            sw.swundef = 1;
  151.            break;
  152. #ifdef TRACE
  153.       case 'x':           /* Trace options for the document body. */
  154.            sw.trace = optarg;
  155.            break;
  156.       case 'y':           /* Trace options for the prolog. */
  157.            sw.ptrace =  optarg;
  158.            break;
  159. #endif /* TRACE */
  160.       case 'v':           /* Print the version number. */
  161.            fprintf(stderr, "sgmls version %s\n", version_string);
  162.            fflush(stderr);
  163.            break;
  164.       case 'o':
  165.            sw.nopen = atol(optarg);
  166.            if (sw.nopen <= 0)
  167.             usage();
  168.            break;
  169.       case 'i':          /* Define parameter entity as "INCLUDE". */
  170.            sw.includes = (char **)xrealloc((UNIV)sw.includes,
  171.                            (nincludes + 2)*sizeof(char *));
  172.            sw.includes[nincludes++] = optarg;
  173.            sw.includes[nincludes] = 0;
  174.            break;
  175.       case '?':
  176.            usage();
  177.       default:
  178.            abort();
  179.       }
  180.      }
  181.      
  182. #ifdef CANT_REDIRECT_STDERR
  183.      if (errfile) {
  184.       FILE *fp;
  185.       errno = 0;
  186.       fp = fopen(errfile, "w");
  187.       if (!fp)
  188.            fatal(E_OPEN, errfile, strerror(errno));
  189.       fclose(fp);
  190.       errno = 0;
  191.       if (!freopen(errfile, "w", stderr)) {
  192.            /* Can't use fatal() since stderr is now closed */
  193.            printf("%s: ", prog);
  194.            printf(errlist[E_OPEN], errfile, strerror(errno));
  195.            putchar('\n');
  196.            exit(EXIT_FAILURE);
  197.       }
  198.      }
  199. #endif /* CANT_REDIRECT_STDERR */
  200.  
  201.      (void)sgmlset(&sw);
  202.  
  203. #ifdef SUPPORT_SUBDOC
  204.      build_subargv(&sw);
  205. #endif
  206.      if (sgmlsdoc(make_docent(argc - optind, argv + optind)))
  207.       fatal(E_DOC);
  208.  
  209.      process_document(sw.nopen > 0);
  210.      sgmlend(&cap);
  211.      if (capfile)
  212.       write_caps(capfile, &cap);
  213. #ifdef SUPPORT_SUBDOC
  214.      cleanup();
  215.      if (suberr)
  216.       exit(EXIT_FAILURE);
  217. #endif /* SUPPORT_SUBDOC */
  218.      if (sgmlgcnterr() > 0)
  219.       exit(EXIT_FAILURE);
  220.      if (!sw.nopen)
  221.       output_conforming();
  222.      exit(EXIT_SUCCESS);
  223. }
  224.  
  225. static char *munge_program_name(arg, dflt)
  226. char *arg, *dflt;
  227. {
  228.      char *p;
  229. #ifdef PROG_STRIP_EXTENSION
  230.      char *ext;
  231. #endif
  232.      if (!arg || !*arg)
  233.       return dflt;
  234.      p = strchr(arg, '\0');
  235.      for (;;) {
  236.       if (p == arg)
  237.            break;
  238.       --p;
  239.       if (strchr(PROG_PREFIX, *p)) {
  240.            p++;
  241.            break;
  242.       }
  243.      }
  244.      arg = p;
  245. #ifdef PROG_STRIP_EXTENSION
  246.      ext = strrchr(arg, '.');
  247.      if (ext) {
  248.       p = (char *)xmalloc(ext - arg + 1);
  249.       memcpy(p, arg, ext - arg);
  250.       p[ext - arg] = '\0';
  251.       arg = p;
  252.      }
  253. #endif /* PROG_STRIP_EXTENSION */
  254. #ifdef PROG_FOLD
  255. #ifdef PROG_STRIP_EXTENSION
  256.      if (!ext) {
  257. #endif
  258.       p = xmalloc(strlen(arg) + 1);
  259.       strcpy(p, arg);
  260.       arg = p;
  261. #ifdef PROG_STRIP_EXTENSION
  262.      }
  263. #endif
  264.      for (p = arg; *p; p++)
  265.       if (ISASCII((unsigned char)*p) && isupper((unsigned char)*p))
  266.            *p = tolower((unsigned char)*p);
  267. #endif /* PROG_FOLD */
  268.      return arg;
  269. }
  270.  
  271. static UNIV make_docent(argc, argv)
  272. int argc;
  273. char **argv;
  274. {
  275.      UNS len = 1;
  276.      int i;
  277.      UNIV res;
  278.      char *ptr;
  279.      static char *stdinname = STDINNAME;
  280.  
  281.      if (argc == 0) {
  282.       argv = &stdinname;
  283.       argc = 1;
  284.      }
  285.  
  286.      for (i = 0; i < argc; i++)
  287.       len += strlen(argv[i]) + 1;
  288.      
  289.      res = xmalloc(len);
  290.      ptr = (char *)res;
  291.      for (i = 0; i < argc; i++) {
  292.       strcpy(ptr, argv[i]);
  293.       ptr = strchr(ptr, '\0') + 1;
  294.      }
  295.      *ptr = '\0';
  296.      return res;
  297. }
  298.  
  299.  
  300. static VOID usage()
  301. {
  302.      /* Don't mention -o since this are for internal use only. */
  303.      fprintf(stderr, "Usage: %s [-deglprsuv]%s [-c file] [-i entity]%s [filename ...]\n",
  304.          prog,
  305. #ifdef CANT_REDIRECT_STDERR
  306.          " [-f file]",
  307. #else /* not CANT_REDIRECT_STDERR */
  308.          "",
  309. #endif /* not CANT_REDIRECT_STDERR */
  310. #ifdef TRACE
  311.          " [-x flags] [-y flags]"
  312. #else /* not TRACE */
  313.          ""
  314. #endif /* not TRACE */
  315.          );
  316.      exit(EXIT_FAILURE);
  317. }
  318.  
  319. static VOID die()
  320. {
  321. #ifdef SUPPORT_SUBDOC
  322.      cleanup();
  323. #endif /* SUPPORT_SUBDOC */
  324.      exit(EXIT_FAILURE);
  325. }
  326.  
  327. static VOID swinit(swp)
  328. struct switches *swp;
  329. {
  330.      swp->swenttr = 0;
  331.      swp->sweltr = 0;
  332.      swp->swbufsz = READCNT+2;
  333.      swp->prog = prog;
  334.      swp->swdupent = 0;
  335.      swp->swrefmsg = 0;
  336. #ifdef TRACE
  337.      swp->trace = 0;
  338.      swp->ptrace = 0;
  339. #endif /* TRACE */
  340.      swp->catd = catd;
  341.      swp->swambig = 1;          /* Always check for ambiguity. */
  342.      swp->swundef = 0;
  343.      swp->nopen = 0;
  344.      swp->onlypro = 0;
  345.      swp->includes = 0;
  346.      swp->die = die;
  347. }
  348.  
  349. #ifdef SUPPORT_SUBDOC
  350.  
  351. static VOID build_subargv(swp)
  352. struct switches *swp;
  353. {
  354.      if (suppsw)
  355.       subargv[subargc++] = "-s";
  356.      if (locsw)
  357.       subargv[subargc++] = "-l";
  358.      if (swp->swdupent)
  359.       subargv[subargc++] = "-d";
  360.      if (swp->swenttr)
  361.       subargv[subargc++] = "-e";
  362.      if (swp->sweltr)
  363.       subargv[subargc++] = "-g";
  364.      if (swp->swrefmsg)
  365.       subargv[subargc++] = "-r";
  366. #ifdef TRACE
  367.      if (swp->trace) {
  368.       subargv[subargc++] = "-x";
  369.       subargv[subargc++] = swp->trace;
  370.      }
  371.      if (swp->ptrace) {
  372.       subargv[subargc++] = "-y";
  373.       subargv[subargc++] = swp->ptrace;
  374.      }
  375. #endif /* TRACE */
  376.      subargv[subargc++] = "-o";
  377.      sprintf(nopenbuf, "%ld", swp->nopen + 1);
  378.      subargv[subargc++] = nopenbuf;
  379. }
  380.  
  381.  
  382. static
  383. VOID handler(sig)
  384. int sig;
  385. {
  386.      signal(sig, SIG_DFL);
  387.      cleanup();
  388.      raise(sig);
  389. }
  390.  
  391. static
  392. VOID cleanup()
  393. {
  394.      if (sgmldecl_file[0]) {
  395.       (void)remove(sgmldecl_file);
  396.       sgmldecl_file[0] = '\0';
  397.      }
  398.      if (subcap_file[0]) {
  399.       (void)remove(subcap_file);
  400.       subcap_file[0] = '\0';
  401.      }
  402. }
  403.  
  404. static
  405. char *store_sgmldecl()
  406. {
  407.      if (!sgmldecl_file[0]) {
  408.       FILE *fp;
  409.       if (signal(SIGINT, SIG_IGN) != SIG_IGN)
  410.            signal(SIGINT, handler);
  411. #ifdef SIGTERM
  412.       if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
  413.            signal(SIGTERM, handler);
  414. #endif /* SIGTERM */
  415. #ifdef SIGPIPE
  416.       if (signal(SIGPIPE, SIG_IGN) != SIG_IGN)
  417.            signal(SIGPIPE, handler);
  418. #endif
  419. #ifdef SIGHUP
  420.       if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
  421.            signal(SIGHUP, handler);
  422. #endif
  423.       tmpnam(sgmldecl_file);
  424.       errno = 0;
  425.       fp = fopen(sgmldecl_file, "w");
  426.       if (!fp)
  427.            fatal(E_OPEN, sgmldecl_file, strerror(errno));
  428.       sgmlwrsd(fp);
  429.       fclose(fp);
  430.      }
  431.      return sgmldecl_file;
  432. }
  433.  
  434. static
  435. char *create_subcap_file()
  436. {
  437.      if (subcap_file[0] == '\0') {
  438.       FILE *fp;
  439.       tmpnam(subcap_file);
  440.       fp = fopen(subcap_file, "w");
  441.       if (!fp)
  442.            fatal(E_OPEN, subcap_file, strerror(errno));
  443.       fclose(fp);
  444.      }
  445.      return subcap_file;
  446. }
  447.  
  448. char **make_argv(id)
  449. UNIV id;
  450. {
  451.      int nfiles;
  452.      char *p;
  453.      char **argv;
  454.      int i;
  455.  
  456.      for (p = (char *)id, nfiles = 0; *p; p = strchr(p, '\0') + 1)
  457.       nfiles++;
  458.      
  459.      argv = (char **)xmalloc((subargc + 2 + 1 + nfiles + 1)*sizeof(char *));
  460.      memcpy((UNIV)argv, (UNIV)subargv, subargc*sizeof(char *));
  461.      
  462.      i = subargc;
  463.  
  464.      argv[i++] = "-c";
  465.      argv[i++] = create_subcap_file();
  466.  
  467.      argv[i++] = store_sgmldecl();
  468.  
  469.      for (p = (char *)id; *p; p = strchr(p, '\0') + 1)
  470.       argv[i++] = p;
  471.      argv[i] = 0;
  472.      return argv;
  473. }
  474.  
  475. VOID get_subcaps()
  476. {
  477.      long cap[NCAPACITY];
  478.      FILE *fp;
  479.      int i;
  480.  
  481.      if (!subcap_file[0])
  482.       return;
  483.      errno = 0;
  484.      fp = fopen(subcap_file, "r");
  485.      if (!fp)
  486.       fatal(E_OPEN, subcap_file, strerror(errno));
  487.      for (i = 0; i < NCAPACITY; i++)
  488.       if (fscanf(fp, "%*s %ld", cap + i) != 1)
  489.            fatal(E_CAPBOTCH);
  490.      fclose(fp);
  491.      sgmlsubcap(cap);
  492. }
  493.  
  494.  
  495. #endif /* SUPPORT_SUBDOC */
  496.  
  497. /* Print capacity statistics.*/
  498.  
  499. static VOID write_caps(name, p)
  500. char *name;
  501. struct sgmlcap *p;
  502. {
  503.      FILE *fp;
  504.      int i;
  505.      fp = fopen(name, "w");
  506.      if (!fp)
  507.       fatal(E_OPEN, name, strerror(errno));
  508.      /* This is in RACT format. */
  509.      for (i = 0; i < NCAPACITY; i++)
  510.       fprintf(fp, "%s %ld\n", p->name[i], p->number[i]*p->points[i]);
  511.      fclose(fp);
  512. }
  513.  
  514. UNIV xmalloc(n)
  515. UNS n;
  516. {
  517.      UNIV p = malloc(n);
  518.      if (!p)
  519.       fatal(E_NOMEM);
  520.      return p;
  521. }
  522.  
  523. UNIV xrealloc(s, n)
  524. UNIV s;
  525. UNS n;
  526. {
  527.      s = s ? realloc(s, n) : malloc(n);
  528.      if (!s)
  529.       fatal(E_NOMEM);
  530.      return s;
  531. }
  532.  
  533. static
  534. #ifdef VARARGS
  535. VOID fatal(va_alist) va_dcl
  536. #else
  537. VOID fatal(int errnum,...)
  538. #endif
  539. {
  540. #ifdef VARARGS
  541.      int errnum;
  542. #endif
  543.      va_list ap;
  544.      
  545. #ifdef VARARGS
  546.      va_start(ap);
  547.      errnum = va_arg(ap, int);
  548. #else
  549.      va_start(ap, errnum);
  550. #endif
  551.      do_error(errnum, ap);
  552.      va_end(ap);
  553.      exit(EXIT_FAILURE);
  554. }
  555.  
  556. #ifdef VARARGS
  557. VOID appl_error(va_alist) va_dcl
  558. #else
  559. VOID appl_error(int errnum,...)
  560. #endif
  561. {
  562. #ifdef VARARGS
  563.      int errnum;
  564. #endif
  565.      va_list ap;
  566.      
  567. #ifdef VARARGS
  568.      va_start(ap);
  569.      errnum = va_arg(ap, int);
  570. #else
  571.      va_start(ap, errnum);
  572. #endif
  573.      do_error(errnum, ap);
  574.      va_end(ap);
  575. }
  576.  
  577. static
  578. VOID do_error(errnum, ap)
  579. int errnum;
  580. va_list ap;
  581. {
  582.      char *text;
  583.      fprintf(stderr, "%s: ", prog);
  584.      assert(errnum > 0);
  585.      assert(errnum < sizeof(errlist)/sizeof(errlist[0]));
  586.      text = catgets(catd, APP_SET, errnum, errlist[errnum]);
  587.      assert(text != 0);
  588.      xvfprintf(stderr, text, ap);
  589.      fputc('\n', stderr);
  590.      fflush(stderr);
  591. }
  592.  
  593. /*
  594. Local Variables:
  595. c-indent-level: 5
  596. c-continued-statement-offset: 5
  597. c-brace-offset: -5
  598. c-argdecl-indent: 0
  599. c-label-offset: -5
  600. comment-column: 30
  601. End:
  602. */
  603.